<?php

namespace Xin\Menu\Laravel;

use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Illuminate\Validation\ValidationException;
use Xin\Menu\AbstractDBRepository;

class ModelRepository extends AbstractDBRepository
{

	/**
	 * 构造一个新的查询器
	 * @return EloquentBuilder
	 */
	protected function newQuery()
	{
		$modelClass = $this->getConfig('model', DatabaseMenu::class);

		return call_user_func([$modelClass, 'query']);
	}

	/**
	 * 使用自定义查询
	 * @return mixed
	 */
	protected function withCustomQuery()
	{
		$query = $this->newQuery();

		$queryCallback = $this->getConfig('query');
		if ($queryCallback) {
			$query = call_user_func($queryCallback, $query);
		}

		return $query;
	}

	/**
	 * 支持搜索的查询器
	 * @param array $search
	 * @return EloquentBuilder
	 */
	protected function newQueryWithSearch($search = [])
	{
		$query = $this->withCustomQuery();
		if (method_exists($query, 'search')) {
			$query = $query->search($search);
		} else {
			$query = $this->buildSearchQuery($query, $search);
		}

		return $query;
	}

	/**
	 * 构建搜索的查询器
	 * @param EloquentBuilder $query
	 * @param array $search
	 * @return EloquentBuilder
	 */
	protected function buildSearchQuery(EloquentBuilder $query, array $search)
	{
		$query->where($search);

		return $query;
	}

	/**
	 * @inerhitDoc
	 */
	protected function getExistKeys(array $keys)
	{
		return $this->newQuery()->whereIn('name', $keys)->pluck('name')->toArray();
	}


	/**
	 * @inerhitDoc
	 */
	public function all(array $search = [])
	{
		$items = $this->newQueryWithSearch($search)->orderBy('sort')->get();

		return $this->optimizeItems($items);
	}

	/**
	 * @inerhitDoc
	 */
	public function get($identifier)
	{
		$item = $this->withCustomQuery()->where('id', $identifier)->first();
		if (empty($item)) {
			return null;
		}

		return $this->optimizeItem($item);
	}

	/**
	 * 优化返回的结果集
	 * @param Collection $items
	 * @return array
	 */
	protected function optimizeItems(Collection $items)
	{
		return $items->map(function (Model $item) {
			return $this->optimizeItem($item);
		})->toArray();
	}

	/**
	 * 优化返回的结果
	 * @param Model $item
	 * @return array
	 */
	protected function optimizeItem(Model $item)
	{
		$item = $item->toArray();
		return $item;
	}

	/**
	 * 优化返回的结果
	 * @param array $data
	 * @return array
	 */
	public function insert(array $data)
	{
		$writerCallback = $this->getConfig('writer');
		if ($writerCallback) {
			call_user_func_array($writerCallback, [&$data]);
		}

		$builder = $this->newQuery();

		return $builder->forceCreate($data)->toArray();
	}

	/**
	 * @inheritDoc
	 */
	public function update($identifier, array $data)
	{
		// 构建查询器
		$builder = $this->withCustomQuery();

		// 查询数据库数据
		$info = $builder->where('id', $identifier)->firstOrFail();
		$info->forceFill($data)->save();

		return $info->toArray();
	}


	/**
	 * @inerhitDoc
	 * @throws ValidationException
	 */
	public function delete($identifier)
	{
		$identifier = (array)$identifier;

		//检查是否有子分类 计算两个数组交集
		$pidList = $this->newQuery()->whereIn('pid', $identifier)->pluck('pid')->toArray();
		$pidList = array_intersect($pidList, $identifier);

		if (!empty($pidList)) {
			$titles = implode("、", $this->newQuery()->whereIn('id', $pidList)->pluck("title")->toArray());
			throw ValidationException::withMessages([
				'default' => "请先删除【{$titles}】下的子菜单！",
			]);
		}

		// 查询要删除的数据是否存在
		return $this->newQuery()->whereIn('id', $identifier)->where('system', '=', 0)->get()->map(function (Model $item) {
			$item->delete();
			return $item->toArray();
		});
	}


	/**
	 * @inerhitDoc
	 */
	public function deleteByApp(string $app)
	{
		$query = $this->newQuery();

		// 查询要删除的数据是否存在
		return $query->where('app', $app)->get()->map(function (Model $item) {
			$item->delete();
			return (array)$item;
		});
	}

	/**
	 * @inerhitDoc
	 */
	public function deleteAll()
	{
		$this->withCustomQuery()->delete();
	}
}
